package com.tsx.millions.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tsx.millions.entity.ActResultLog;
import com.tsx.millions.entity.vo.ActResultLogResponse;
import com.tsx.millions.mapper.ActResultLogMapper;
import com.tsx.millions.service.ActResultLogService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author sx.tong
 * @description 针对表【act_result_log(操作结果日志表)】的数据库操作Service实现
 * @createDate 2025-08-01 15:48:02
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ActResultLogServiceImpl extends ServiceImpl<ActResultLogMapper, ActResultLog>
        implements ActResultLogService {

    private final ThreadPoolExecutor exportThreadPoolExecutor;
    private final ActResultLogMapper actResultLogMapper;

    @Override
    public void export(HttpServletResponse httpServletResponse) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        // 获取 JVM 当前内存状态
        Runtime runtime = Runtime.getRuntime();
        long beforeUsedMemory = runtime.totalMemory() - runtime.freeMemory();

        // 获取总记录数
        long count = this.count();
        int pageSize = 100000; // 每页大小，可以根据实际情况调整
        // 计算总页数
        long totalPage = count == 0 ? 1 : (count + pageSize - 1) / pageSize;

        // 设置响应头
        setResponseHeaders("act_result_log", httpServletResponse);
        List<CompletableFuture<List<ActResultLogResponse>>> futures = new ArrayList<>();

        // 初始化 ExcelWriter
        try (ExcelWriter excelWriter = EasyExcel.write(httpServletResponse.getOutputStream(), ActResultLogResponse.class).build()) {
            for (long pageIndex = 0; pageIndex < totalPage; pageIndex++) {
                long currentSize = pageIndex * pageSize;
                CompletableFuture<List<ActResultLogResponse>> future = CompletableFuture.supplyAsync(() -> actResultLogMapper.pageQuery(currentSize, pageSize), exportThreadPoolExecutor);
                futures.add(future);
            }
            // 等待所有的 future 完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

            // 处理完成后的数据
            for (int pageIndex = 0; pageIndex < futures.size(); pageIndex++) {
                List<ActResultLogResponse> actResultLogResponseList = futures.get(pageIndex).get();
                WriteSheet writeSheet = EasyExcel.writerSheet(pageIndex, "Sheet-" + (pageIndex + 1)).build();
                excelWriter.write(actResultLogResponseList, writeSheet);
            }
        } catch (Exception e) {
            throw new RuntimeException("导出失败", e);
        } finally {
            stopWatch.stop();
            long afterUsedMemory = runtime.totalMemory() - runtime.freeMemory();
            long memoryUsed = afterUsedMemory - beforeUsedMemory;
            log.info("ActResultLogServiceImpl.export memoryUsed: {}MB, ttl: {}ms",
                    memoryUsed / (1024 * 1024), stopWatch.getTotalTimeMillis());
        }
    }

    /**
     * 设置响应头
     *
     * @param fileName 文件名
     * @param response HTTP 响应
     */
    private void setResponseHeaders(String fileName, HttpServletResponse response) {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
        response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName + ".xlsx");
    }
}




